import cv2 as cv
import numpy as np


class Contour:
    """查找轮廓"""
    def __init__(self):
        self.img = None
        self.img_plus = None
        self.init_img()

    def init_img(self):
        self.img = cv.imread("img/shape.jpg", cv.IMREAD_COLOR)
        self.img_plus = cv.imread("img/tenis1.jpg", cv.IMREAD_COLOR)

    def find_contour(self):
        cv.imshow("img", self.img)
        gray_img = cv.cvtColor(self.img, cv.COLOR_BGR2GRAY)
        cv.imshow("gray img", gray_img)

        # 获得二值图片
        # binary_img = cv.adaptiveThreshold(gray_img,
        #                                   255,
        #                                   cv.ADAPTIVE_THRESH_GAUSSIAN_C,
        #                                   cv.THRESH_BINARY, 5, 2)
        _, binary_img = cv.threshold(gray_img, 240, 250, cv.THRESH_BINARY_INV)
        cv.imshow("binary img", binary_img)

        # 找轮廓
        """
        轮廓检索模式:
        RETR_EXTERNAL	只检测最外层轮廓
        RETR_LIST	提取所有轮廓，并放置在list中，检测的轮廓不建立等级关系
        RETR_CCOMP	提取所有轮廓，并将轮廓组织成双层结构(two-level hierarchy),顶层为连通域的外围边界，次层位内层边界
        RETR_TREE	提取所有轮廓并重新建立网状轮廓结构
        轮廓检索算法:
        CHAIN_APPROX_NONE	获取每个轮廓的每个像素，相邻的两个点的像素位置差不超过1
        CHAIN_APPROX_SIMPLE	压缩水平方向，垂直方向，对角线方向的元素，只保留该方向的重点坐标，如果一个矩形轮廓只需4个点来保存轮廓信息
        CHAIN_APPROX_TC89_L1	Teh-Chinl链逼近算法
        CHAIN_APPROX_TC89_KCOS	Teh-Chinl链逼近算法
        """
        contours, hierarchy = cv.findContours(binary_img, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_TC89_KCOS)
        print(contours, hierarchy)

        # 画轮廓
        index = -1  # 所有的轮廓
        thickness = 2  # 轮廓的宽度
        color = (255, 125, 125)  # 轮廓的颜色
        cv.drawContours(self.img, contours, index, color, thickness)
        cv.imshow('draw contours', self.img)

        # 获取轮廓属性
        for c in contours:
            # 计算面积
            area = cv.contourArea(c)
            print("area:", area)
            # 该函数计算曲线长度或闭合轮廓周长。
            perimeter = cv.arcLength(c, True)
            print("perimeter", perimeter)
            # 获取最小的外切圆
            ((x, y), radius) = cv.minEnclosingCircle(c)
            # 绘制外接圆
            cv.circle(self.img, (int(x), int(y)), int(radius), (0, 0, 255), 2)
            # 外接矩形
            x_rect, y_rect, width, height = cv.boundingRect(c)
            # 绘制外接矩形
            cv.rectangle(self.img, (x_rect, y_rect), (x_rect + width, y_rect + height), (0,255,0), 2)
            cv.imshow("circle_img", self.img)

    def find_contour_plus(self):
        cv.imshow("self_img_plus", self.img_plus)

        # 定义范围
        lower_color = (30, 120, 130)
        upper_color = (60, 255, 255)
        # 查找颜色
        hsv_img = cv.cvtColor(self.img_plus, cv.COLOR_BGR2HSV)
        mask_img = cv.inRange(hsv_img, lower_color, upper_color)
        cv.imshow("mask img", mask_img)

        # bgr_img = cv.cvtColor(mask_img, cv.COLOR_HSV2BGR)
        # gray_img = cv.cvtColor(bgr_img, cv.COLOR_BGR2GRAY)
        # # 采用高斯滤波去掉噪点
        # gray_img = cv.GaussianBlur(gray_img, (5, 5), 0)
        # cv.imshow("gray img", gray_img)
        #
        # binary_img = cv.adaptiveThreshold(gray_img, 255, cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY_INV, 5, 2)
        # cv.imshow("binary img", binary_img)
        contours, hierarchy = cv.findContours(mask_img, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
        print(contours, hierarchy)
        self.process_tenis_contours(self.img_plus, contours)
        return self.img_plus, contours

    @staticmethod
    def process_tenis_contours(bgr_img, contours):
        black_img = np.zeros([bgr_img.shape[0], bgr_img.shape[1], 3], np.uint8)

        for c in contours:
            # 计算面积
            area = cv.contourArea(c)
            # 该函数计算曲线长度或闭合轮廓周长。
            perimeter = cv.arcLength(c, True)
            # 获取最小的外切圆
            ((x, y), radius) = cv.minEnclosingCircle(c)

            # 绘制轮廓
            cv.drawContours(bgr_img, [c], -1, (150, 250, 150), 2)
            cv.drawContours(black_img, [c], -1, (150, 250, 150), 2)
            # 获取轮廓中心点
            # cx,cy = get_contour_center(c)
            # print(cx,cy)
            x = int(x)
            y = int(y)
            cv.circle(bgr_img, (x, y), int(radius), (0, 0, 255), 2)
            cv.circle(black_img, (x, y), int(radius), (0, 0, 255), 2)

            print("Area:{},primeter:{}".format(area, perimeter))

        print("number of contours:{}".format(len(contours)))
        cv.imshow("rgb img contours", bgr_img)
        cv.imshow("black img contours", black_img)


if __name__ == '__main__':
    Contour().find_contour()
    # Contour().find_contour_plus()
    # 让程序处于等待推出状态
    cv.waitKey(0)
    # 当程序推出时，释放所有窗口资源
    cv.destroyAllWindows()